package proyectofinal_diseno;

/**
 * @author Katherine Vargas
 * @author Esteban Herrera
 */


class Caballo
{
	private final int [][] PASOS = {{2, 1}, {1, 2}, {-1, 2}, {-2, 1},
                                   {-2, -1}, {-1, -2}, {1, -2}, {2, -1}};
	private Punto posicion;

	Caballo (Punto ubicacion, Matriz miMatriz)
	{
		puestoEn (ubicacion, miMatriz);
	}

	int[][] getPasos()
	{
		return PASOS;
	}

	private void puestoEn (Punto ubicacion, Matriz miMatriz)
	{
		posicion = new Punto (ubicacion);
		miMatriz.poneCaballo (posicion);
	}

	boolean puedeMover (Matriz miMatriz) 
	{
		return posicion.numQueExiste (this, miMatriz) > 0;
	}

   	void mover (Matriz miMatriz) 
	{
		int minExiste = minNumQueExiste (miMatriz);
		int posibilidades = numDePuntos (minExiste, miMatriz);
		int alazar = (int) (posibilidades * Math.random() + 1);
		Punto siguiente = nuevaLocalizacion (alazar, miMatriz, minExiste);
		puestoEn (siguiente, miMatriz);
	}

	private int minNumQueExiste (Matriz miMatriz)
	{
            int existe = PASOS.length + 1;
            for (int i=0; i < PASOS.length; i++)
            {
                Punto siguiente = posicion.trasladar (getPasos()[i]);
                if (siguiente.enMatriz (miMatriz) && !siguiente.visitado (miMatriz)) 
                {
                    existe = Math.min (existe, siguiente.numQueExiste (this, miMatriz));
                }
            }
            return existe;
        }
   
   private int numDePuntos (int existe, Matriz miMatriz)
   {
      int numero = 0;
      for (int i=0; i < PASOS.length; i++)
      {
         Punto siguiente = posicion.trasladar (getPasos()[i]);
         if (siguiente.enMatriz (miMatriz) && !siguiente.visitado (miMatriz)
                && siguiente.numQueExiste (this, miMatriz) == existe) 
         {
              numero++;
         }
      }
      return numero;
   }
   
   private Punto nuevaLocalizacion (int alazar, Matriz miMatriz, int existe)
   {
      int numero = 0, i = 0;
      Punto siguiente = new Punto();
      while (numero < alazar)
      {
         siguiente = posicion.trasladar (getPasos()[i]);
         if (siguiente.enMatriz (miMatriz) && !siguiente.visitado (miMatriz)
                && siguiente.numQueExiste (this, miMatriz) == existe)
         {
            numero++;
         }
         i++;
      }
      return siguiente;
   }
}

class Matriz
{
	private final int TAMANO;
	private int[][] tiempoDeVisita;
	private int numPuntosVisitados;
   
	Matriz (int TAM_MATRIZ)
	{
		TAMANO = TAM_MATRIZ;
		tiempoDeVisita = new int [TAMANO] [TAMANO];
		for (int i=0; i < TAMANO; i++) 
                {
                    for (int j=0; j < TAMANO; j++) 
                    {
                        tiempoDeVisita [i][j] = 0;
                    }
                }
		numPuntosVisitados = 0;
	}

	int getDimension()
	{
		return TAMANO;
	}

	int getTiempoDeVisita (int x, int y)
	{
		return tiempoDeVisita[x][y];
	}

	void poneCaballo (Punto P) 
	{
		numPuntosVisitados++;
		tiempoDeVisita [P.getX()] [P.getY()] = numPuntosVisitados;
	}

        @Override
	public String toString()
	{
		String resultado = "";
		for (int row=TAMANO-1; row >= 0; row--)
		{
			for (int col=0; col < TAMANO; col++)
			{
				if (tiempoDeVisita [col][row] < 10) 
                                {
                                resultado += " ";
                                }
				resultado += tiempoDeVisita [col][row] + " ";
			}
			resultado += "\n";
		}
      return resultado;
	}
}

class Punto
{
        private int x, y;

	Punto ()
	{}

	Punto (int x, int y)
	{
		this.x = x;
		this.y = y;
	}

	Punto (Punto P)
	{
		x = P.x;
		y = P.y;
	}

	int getX()
	{
		return x;
	}

	int getY()
	{
		return y;
	}

	Punto trasladar (int[] traslacion)
	{
		return new Punto (x + traslacion[0], y + traslacion[1]);
	}

	boolean enMatriz (Matriz miMatriz) 
	{
		return 0 <= x & x < miMatriz.getDimension() & 0 <= y & y < miMatriz.getDimension();
	}

	boolean visitado (Matriz miMatriz) 
	{
		return miMatriz.getTiempoDeVisita(x, y) != 0;
	}
        
        int numQueExiste (Caballo miCaballo, Matriz miMatriz)
	{
		int resultado = 0;
		for (int i=0; i < miCaballo.getPasos().length; i++)
		{
			Punto siguiente = trasladar (miCaballo.getPasos()[i]);
			if (siguiente.enMatriz (miMatriz) && !siguiente.visitado (miMatriz)) 
                        {
                            resultado++;
                        }
		}
        return resultado;
	}
}